/*
** Implementation of a guassian process equivalent to maxent
*/

// third party c includes
#include <mpi.h>
#include <math.h>
#include <time.h>

// third party c++ includes
#include <iostream>
#include <fstream>
#include <sstream>
#include <assert.h>

// local includes
#include "crf_learn.h"
#include "crf_minable.h"
#include "flat_minable.h"
#include "param.h"
#include "util.h"
#include "data.h"

boost::shared_array<double> crf_learn(GPParameter *param, EventsPtr data, 
             const std::string &model_in, const std::string &model_out)
{
	int rank;
	MPI_Comm_rank(MPI_COMM_WORLD, &rank);

    CRFMinablePtr crf_minable(new CRFMinable(data, param));
    boost::shared_array<double> alpha 
		= _crf_learn(param, crf_minable, model_in);

	if (rank ==0 && model_out != "")
    {
        std::cout << "\n-- Serialising parameters --" << std::endl;
        std::ofstream fd(model_out.c_str());
        serialise1d(fd, alpha.get(), param->n);
    }

//    boost::shared_ptr<T> classifier(new T(data, alpha, param));
//    return classifier;
    return alpha;
}

boost::shared_array<double> flat_learn(GPParameter *param, FlatEventsPtr data, 
             const std::string &model_in, const std::string &model_out)
{
	int rank;
	MPI_Comm_rank(MPI_COMM_WORLD, &rank);

    FlatMinablePtr crf_minable(new FlatMinable(data, param));
    boost::shared_array<double> alpha 
		= _crf_learn(param, crf_minable, model_in);

	if (rank ==0 && model_out != "")
    {
        std::cout << "\n-- Serialising parameters --" << std::endl;
        std::ofstream fd(model_out.c_str());
        serialise1d(fd, alpha.get(), param->n);
    }

//    boost::shared_ptr<T> classifier(new T(data, alpha, param));
//    return classifier;
    return alpha;
}

boost::shared_array<double> _crf_learn(GPParameter *param, 
	CRFMinablePtr crf_minable, const std::string &weights_file)
{
    int rank;
    MPI_Comm_rank(MPI_COMM_WORLD, &rank);

    std::ifstream fd(weights_file.c_str());
    if (fd.good())
    {
        if (rank == 0)
			std::cout << "--- Setting initial parameters from " << weights_file 
				<< std::endl;
        std::ifstream fd(weights_file.c_str());
        int alpha_length=0;

        // read the parameters from the file
		double *tmp=0;
        deserialise1d(fd, tmp, alpha_length);
		crf_minable->m_weights.reset(tmp);
        fd.close();
    }

    crf_minable->m_iterations = param->max_its;
	
	// run the inference algorithm
    crf_minable->minimise();

    return crf_minable->m_weights;
}
